﻿using Furion;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Newtonsoft.Json.Serialization;
using Queer.Util;
using Queer.Util.Helper;
using Queer.WebApi.Handlers;
using Senparc.CO2NET;
using Senparc.CO2NET.AspNet;
using Senparc.Weixin;
using Senparc.Weixin.Cache.Redis;
using Senparc.Weixin.Entities;
using Senparc.Weixin.MP;
using Senparc.Weixin.RegisterServices;
using Senparc.Weixin.TenPay;
using Senparc.Weixin.WxOpen;

namespace Queer.WebApi
{
    [AppStartup(2)]
    public class ApiStartup : AppStartup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddCorsAccessor();

            // JWT 验证
            services.AddJwt<JwtHandler>(enableGlobalAuthorize: true);

            services.AddControllers()
                    .AddNewtonsoftJson(options =>
                    {
                        // 返回数据首字母不小写，CamelCasePropertyNamesContractResolver是小写
                        options.SerializerSettings.ContractResolver = new DefaultContractResolver();
                    })
                    .AddInjectWithUnifyResult()
                    .AddFriendlyException() // 注册友好异常服务
                    .AddUnifyResult<ExResultProvider>();

            // 注册拦截器
            services.AddScoped<Queer.WebApi.Areas.Admin.AuthorizeFilterAttribute>();
            services.AddScoped<Queer.WebApi.Areas.WeixinOpen.AuthorizeFilterAttribute>();

            services.Configure<IISServerOptions>(options => options.AllowSynchronousIO = true);

            services.AddMemoryCache(); //使用本地缓存必须添加
            services.AddSenparcWeixinServices(App.Configuration)//Senparc.Weixin 注册（必须）
                  ;
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IOptions<SenparcSetting> senparcSetting, IOptions<SenparcWeixinSetting> senparcWeixinSetting)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseCorsAccessor();

            #region 盛派微信配置（代码位置需要注意）

            // 启动 CO2NET 全局注册，必须！
            // 关于 UseSenparcGlobal() 的更多用法见 CO2NET Demo：https://github.com/Senparc/Senparc.CO2NET/blob/master/Sample/Senparc.CO2NET.Sample.netcore3/Startup.cs
            var registerService = app.UseSenparcGlobal(env, senparcSetting.Value, globalRegister =>
            {
                // CO2NET 全局配置

                #region 全局缓存配置（按需）

                //当同一个分布式缓存同时服务于多个网站（应用程序池）时，可以使用命名空间将其隔离（非必须）
                globalRegister.ChangeDefaultCacheNamespace("Szyl");

                // 配置和使用 Redis          -- DPBMARK Redis

                //配置全局使用Redis缓存（按需，独立）
                if (GlobalContext.SystemConfig.CacheType.ToLower() == "redis")
                {
                    // 注册 StackExchange.Redis
                    Senparc.CO2NET.Cache.Redis.Register.SetConfigurationOption(GlobalContext.SystemConfig.RedisConnectionString);
                    Senparc.CO2NET.Cache.Redis.Register.UseKeyValueRedisNow();//键值对缓存策略（推荐）
                }

                #endregion

                // 注册日志（按需，建议）
                globalRegister.RegisterTraceLog(ConfigTraceLog);

            }, true)
                //使用 Senparc.Weixin SDK
                .UseSenparcWeixin(senparcWeixinSetting.Value, weixinRegister =>
                {
                    #region 微信相关配置

                    /* 微信配置开始
                    * 
                    * 建议按照以下顺序进行注册，尤其须将缓存放在第一位！
                    */

                    #region 微信缓存（按需，必须放在配置开头，以确保其他可能依赖到缓存的注册过程使用正确的配置）

                    //注意：如果使用非本地缓存，而不执行本块注册代码，将会收到“当前扩展缓存策略没有进行注册”的异常

                    //微信的 Redis 缓存，如果不使用则注释掉（开启前必须保证配置有效，否则会抛错）         -- DPBMARK Redis
                    if (GlobalContext.SystemConfig.CacheType.ToLower() == "redis")
                    {
                        weixinRegister.UseSenparcWeixinCacheRedis();
                    }                                                                                     // DPBMARK_END

                    #endregion

                    #region 注册公众号或小程序（按需）

                    weixinRegister
                            //注册公众号（可注册多个）                                                    -- DPBMARK MP

                            .RegisterMpAccount(senparcWeixinSetting.Value, "【盛派网络小助手】公众号")     // DPBMARK_END

                            //注册多个公众号或小程序（可注册多个）                                        -- DPBMARK MiniProgram
                            .RegisterWxOpenAccount(senparcWeixinSetting.Value, "【盛派网络小助手】小程序")// DPBMARK_END

                            //使用 appsettings.json 中的多重配置，再注册一个小程序（其他公众号、企业号类同）                             -- DPBMARK MiniProgram
                            // .RegisterWxOpenAccount(senparcWeixinSetting.Value.Items["第二个小程序"], "第二个【盛派网络小助手】小程序")   // DPBMARK_END

                            //除此以外，仍然可以在程序任意地方注册公众号或小程序：
                            //AccessTokenContainer.Register(appId, appSecret, name);//命名空间：Senparc.Weixin.MP.Containers
                    #endregion

                    #region 注册微信支付（按需）        -- DPBMARK TenPay

                            //注册旧微信支付版本（V2）（可注册多个）
                            .RegisterTenpayOld(senparcWeixinSetting.Value, "【盛派网络小助手】公众号")//这里的 name 和第一个 RegisterMpAccount() 中的一致，会被记录到同一个 SenparcWeixinSettingItem 对象中

                            //注册最新微信支付版本（V3）（可注册多个）
                            .RegisterTenpayV3(senparcWeixinSetting.Value, "【盛派网络小助手】公众号")//记录到同一个 SenparcWeixinSettingItem 对象中
                        /* 特别注意：
                         * 在 services.AddSenparcWeixinServices() 代码中，已经自动为当前的 
                         * senparcWeixinSetting  对应的TenpayV3 配置进行了 Cert 证书配置，
                         * 如果此处注册的微信支付信息和默认 senparcWeixinSetting 信息不同，
                         * 请在 ConfigureServices() 方法中使用 services.AddCertHttpClient() 
                         * 添加对应证书。
                         */

                    #endregion                          // DPBMARK_END

                        ;

                    /* 微信配置结束 */

                    #endregion
                });

            #endregion

            app.UseAuthentication();
            app.UseAuthorization();//需要在注册微信 SDK 之后执行

            app.UseInject();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });

            // 记录启动的日志
            GlobalContext.LogWhenStart(env);
        }

        #region 其他方法

        /// <summary>
        /// 配置微信跟踪日志（演示，按需）
        /// </summary>
        private void ConfigTraceLog()
        {
            //这里设为Debug状态时，/App_Data/WeixinTraceLog/目录下会生成日志文件记录所有的API请求日志，正式发布版本建议关闭

            //如果全局的IsDebug（Senparc.CO2NET.Config.IsDebug）为false，此处可以单独设置true，否则自动为true
            Senparc.CO2NET.Trace.SenparcTrace.SendCustomLog("系统日志", "盛派微信SDK启动了");//只在Senparc.Weixin.Config.IsDebug = true的情况下生效

            //当发生基于WeixinException的异常时触发
            WeixinTrace.OnWeixinExceptionFunc = ex =>
            {
                LogHelper.Error(ex);
            };
        }

        #endregion

    }
}